package net.basshista.jsshtunneling.dao;

import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.security.InvalidKeyException;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;

import net.basshista.jsshtunneling.Main;
import net.basshista.jsshtunneling.utils.EncryptUtils;

public class Dao<T extends Serializable> {

    private static final String USER_HOME;
    private static final String APPLICATION_DIRECTORY = ".jsshtunneling";

    private Class<T> clazz;

    protected File persistentFile;

    public Dao(Class<T> clazz) {
	this.clazz = clazz;
	persistentFile = new File(USER_HOME + File.separator + APPLICATION_DIRECTORY + File.separator + formatName());
    }

    static {
	USER_HOME = System.getProperty("user.home");
    }

    public boolean persistentfileExists() {
	return persistentFile.exists();
    }

    public boolean createFile() throws IOException {
	if (!persistentfileExists()) {
	    if (new File(persistentFile.getParent()).mkdirs())
		return persistentFile.createNewFile();
	}
	return false;
    }

    private String formatName() {
	String className = clazz.getSimpleName().toLowerCase();
	if (className.endsWith("bean")) {
	    className = className.substring(0, className.length() - 4);
	}
	return className;
    }

    public boolean persist(Object obj) throws Exception {
	if (!persistentfileExists()) {
	    createFile();
	}

	FileOutputStream fout = null;

	try {
	    ByteArrayOutputStream memOut = new ByteArrayOutputStream();

	    XMLEncoder encoder = new XMLEncoder(memOut);
	    encoder.writeObject(obj);
	    encoder.close();

	    byte[] enc = EncryptUtils.encrypt(memOut.toByteArray(), Main.key);

	    memOut.close();
	    memOut = null;

	    fout = new FileOutputStream(persistentFile);
	    fout.write(enc);

	    enc = null;

	    return true;
	} catch (Exception e) {
	    throw e;
	} finally {
	    if (fout != null)
		fout.close();
	}
    }

    @SuppressWarnings("unchecked")
    public T retrive() throws IOException, ClassNotFoundException {
	if (!persistentfileExists())
	    return null;

	FileInputStream fin = null;

	try {

	    fin = new FileInputStream(persistentFile);

	    byte[] bytes = new byte[fin.available()];
	    fin.read(bytes);

	    byte[] desc = EncryptUtils.decrypt(bytes, Main.key);

	    ByteArrayInputStream bin = new ByteArrayInputStream(desc);

	    XMLDecoder decoder = new XMLDecoder(bin);

	    Object res = decoder.readObject();

	    decoder.close();

	    return (T) res;

	} catch (IOException e) {
	    throw e;
	} catch (InvalidKeyException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	} catch (IllegalBlockSizeException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	} catch (BadPaddingException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	} finally {
	    if (fin != null)
		fin.close();
	}

	return null;
    }
}